import { Injectable } from '@nestjs/common';
import { Response } from 'express';
import { ResultData } from 'src/common/utils/result';
import { CacheEnum } from 'src/common/enum/index';
import { ExportTable } from 'src/common/utils/export';
import { CreateDictTypeDto, UpdateDictTypeDto, ListDictType, CreateDictDataDto, UpdateDictDataDto, ListDictData } from './dto/index';
import { RedisService } from 'src/module/common/redis/redis.service';
import { PrismaService } from '@/module/common/prisma/prisma.service';
import { pickEquals, pickLike } from '@/common/utils/prisma';
import { Cacheable, CacheEvict } from '@/common/decorators/redis.decorator';
@Injectable()
export class DictService {
    constructor(
        private readonly redisService: RedisService,
        private readonly prisma: PrismaService,
    ) { }
    async createType(CreateDictTypeDto: CreateDictTypeDto) {
        await this.prisma.dictType.create({
            data: CreateDictTypeDto
        })
        return ResultData.ok();
    }

    async deleteType(dictIds: number[]) {
        await this.prisma.dictType.updateMany({
            where: {
                dictId: { in: dictIds }
            },
            data: { delFlag: '1' }
        })
        return ResultData.ok();
    }

    async updateType(updateDictTypeDto: UpdateDictTypeDto) {
        await this.prisma.dictType.update({
            where: {
                dictId: updateDictTypeDto.dictId
            },
            data: updateDictTypeDto
        })
        return ResultData.ok();
    }

    async findAllType(query: ListDictType) {
        let where: any = {
            delFlag: '0',
            ...pickLike(query, ['dictName', 'dictType']),
            ...pickEquals(query, ['status'])
        }
        if (query?.beginTime && query?.endTime) {
            where.createTime = {
                gte: new Date(query.beginTime),
                lte: new Date(query.endTime),
            }
        }

        let skip = query.pageSize && query.pageNum ? query.pageSize * (query.pageNum - 1) : undefined;
        let take = query.pageSize ? +query.pageSize : undefined
        const [list, total] = await Promise.all([
            this.prisma.dictType.findMany({
                where,
                skip,
                take
            }),
            this.prisma.dictType.count({
                where
            })
        ])
        return ResultData.ok({
            list,
            total,
        });
    }

    async findOneType(dictId: number) {
        const data = await this.prisma.dictType.findUnique({
            where: {
                dictId,
                delFlag: '0'
            }
        })
        return ResultData.ok(data);
    }

    async findOptionselect() {
        const data = await this.prisma.dictType.findMany({
            where: {
                delFlag: '0',
            },
        });
        return ResultData.ok(data);
    }

    // 字典数据
    @CacheEvict(CacheEnum.SYS_DICT_KEY, '{createDictDataDto.dictType}')
    async createDictData(createDictDataDto: CreateDictDataDto) {
        await this.prisma.dictData.create({
            data: createDictDataDto
        })
        return ResultData.ok();
    }
    @CacheEvict(CacheEnum.SYS_DICT_KEY, '*')
    async deleteDictData(dictIds: number[]) {
        await this.prisma.dictData.updateMany({
            where: {
                dictCode: { in: dictIds }
            },
            data: { delFlag: '1' }
        })
        return ResultData.ok();
    }
    @CacheEvict(CacheEnum.SYS_DICT_KEY, '{updateDictDataDto.dictType}')
    async updateDictData(updateDictDataDto: UpdateDictDataDto) {
        await this.prisma.dictData.updateMany({
            where: {
                dictCode: updateDictDataDto.dictCode
            },
            data: updateDictDataDto
        })
        return ResultData.ok();
    }

    async findAllData(query: ListDictData) {
        let where: any = {
            delFlag: '0',
            ...pickLike(query, ['dictLabel', 'dictType']),
            ...pickEquals(query, ['status'])
        }
        let skip = void 0
        let take = void 0
        if (query.pageSize && query.pageNum) {
            skip = query.pageSize * (query.pageNum - 1)
            take = +query.pageSize
        }

        const [list, total] = await Promise.all([
            this.prisma.dictData.findMany({
                where,
                skip,
                take
            }),
            this.prisma.dictData.count({
                where
            })
        ]);

        return ResultData.ok({
            list,
            total,
        });
    }

    /**
     * 根据字典类型查询一个数据类型的信息。
     *
     * @param dictType 字典类型字符串。
     * @returns 返回查询到的数据类型信息，如果未查询到则返回空。
     */
    async findOneDataType(dictType: string) {
        // TODO: 先查询字典类型是否被删除，以下代码被注释
        // const dictTypeData = await this.sysDictTypeEntityRep.findOne({
        //   where: {
        //     dictType: dictType,
        //     delFlag: '0',
        //   },
        // });

        // 尝试从Redis缓存中获取字典数据
        let data = await this.redisService.get(`${CacheEnum.SYS_DICT_KEY}${dictType}`);

        if (data) {
            // 如果缓存中存在，则直接返回缓存数据
            return ResultData.ok(data);
        }

        // 从数据库中查询字典数据
        data = await this.prisma.dictData.findMany({
            where: {
                dictType,
                delFlag: '0',
            },
        });
        // 将查询到的数据存入Redis缓存，并返回数据
        await this.redisService.set(`${CacheEnum.SYS_DICT_KEY}${dictType}`, data);
        return ResultData.ok(data);
    }

    async findOneDictData(dictCode: number) {
        const data = await this.prisma.dictData.findUnique({
            where: {
                dictCode,
                delFlag: '0',
            },
        });
        return ResultData.ok(data);
    }

    /**
     * 导出字典数据为xlsx文件
     * @param res
     */
    async export(res: Response, body: ListDictType) {
        delete body.pageNum;
        delete body.pageSize;
        const list = await this.findAllType(body);
        const options = {
            sheetName: '字典数据',
            data: list.data.list,
            header: [
                { title: '字典主键', dataIndex: 'dictId' },
                { title: '字典名称', dataIndex: 'dictName' },
                { title: '字典类型', dataIndex: 'dictType' },
                { title: '状态', dataIndex: 'status' },
            ],
        };
        ExportTable(options, res);
    }

    /**
     * 导出字典数据为xlsx文件
     * @param res
     */
    async exportData(res: Response, body: ListDictType) {
        delete body.pageNum;
        delete body.pageSize;
        const list = await this.findAllData(body);
        const options = {
            sheetName: '字典数据',
            data: list.data.list,
            header: [
                { title: '字典主键', dataIndex: 'dictCode' },
                { title: '字典名称', dataIndex: 'dictLabel' },
                { title: '字典类型', dataIndex: 'dictValue' },
                { title: '备注', dataIndex: 'remark' },
            ],
        };
        ExportTable(options, res);
    }

    /**
     * 刷新字典缓存
     * @returns
     */
    async resetDictCache() {
        await this.clearDictCache();
        await this.loadingDictCache();
        return ResultData.ok();
    }

    /**
     * 删除字典缓存
     * @returns
     */
    async clearDictCache() {
        const keys = await this.redisService.keys(`${CacheEnum.SYS_DICT_KEY}*`);
        if (keys && keys.length > 0) {
            await this.redisService.del(keys);
        }
    }

    /**
     * 加载字典缓存
     * @returns
     */
    async loadingDictCache() {

        try {
            // 查询 sys_dict_type 表，并关联 sys_dict_data 表
            const list = await this.prisma.dictType.findMany({
                where: {
                    delFlag: '0', // 过滤 delFlag 为 '0' 的记录
                },
                include: {
                    dictData: true, // 关联查询 sys_dict_data 表
                },
            });
            // 遍历结果，存储到 Redis
            list.forEach((item) => {
                if (item.dictType) {
                    this.redisService.set(`${CacheEnum.SYS_DICT_KEY}${item.dictType}`, item.dictData);
                }
            });

            console.log('Dict cache loaded successfully.');
        } catch (error) {
            console.error('Error loading dict cache:', error);
        }
    }
}
